#include "ftp.h"  
#include <sstream>
#include <iostream>
#include <iomanip>
#include <vector>  
static int SplitString( std::string strSrc, std::list<std::string> &strArray , std::string strFlag)  
{  
    int pos = 1;   
  
    while((pos = (int)strSrc.find_first_of(strFlag.c_str())) > 0)   
    {  
        strArray.insert(strArray.end(), strSrc.substr(0 , pos));  
        strSrc = strSrc.substr(pos + 1, strSrc.length() - pos - 1);   
    }  
  
    strArray.insert(strArray.end(), strSrc.substr(0, strSrc.length()));  
  
    return 0;   
}  
  
CFTPManager::CFTPManager(void): m_bLogin(false)  
{  
    m_cmdSocket = socket(AF_INET, SOCK_STREAM, 0);  
      
}  
  
CFTPManager::~CFTPManager(void)  
{  
    std::string strCmdLine = parseCommand(FTP_COMMAND_QUIT, "");  
  
    Send(m_cmdSocket, strCmdLine.c_str());  
    close(m_cmdSocket);  
    m_bLogin = false;  
}  
  
FTP_API CFTPManager::login2Server(const std::string &serverIP)  
{  
    std::string strPort;  
    int pos = serverIP.find_first_of(":");  
  
    if (pos > 0)  
    {  
        strPort = serverIP.substr(pos + 1, serverIP.length() - pos);  
    }  
    else  
    {  
        pos = serverIP.length();  
        strPort = FTP_DEFAULT_PORT;  
    }  
  
    m_strServerIP = serverIP.substr(0, pos);  
    m_nServerPort = atol(strPort.c_str());  
  
    cli_app_log(CLI_LOG_INFO, "IP: %s port: %d\n", m_strServerIP.c_str(), m_nServerPort);  
  
    if (Connect(m_cmdSocket, m_strServerIP, m_nServerPort) < 0)  
    {  
          
        return FTP_FAILED;  
    }  
      
    m_strResponse = serverResponse(m_cmdSocket);  
    if (m_strResponse.empty())
    {
        cli_app_log(CLI_LOG_NOTICE, "ftp response is empty \n");
        return FTP_FAILED;
    }
    cli_app_log(CLI_LOG_INFO, "@@@@Response: %s", m_strResponse.c_str());  
  
    if (parseResponse(m_strResponse) == 220)
    {
        return FTP_SUCCESS;
    }
    else
    {
        cli_app_log(CLI_LOG_NOTICE, "ftp response is not correct %s \n",  m_strResponse.c_str());
        return FTP_FAILED;
    }
}  
  
FTP_API CFTPManager::inputUserName(const std::string &userName)  
{  
    std::string strCommandLine = parseCommand(FTP_COMMAND_USERNAME, userName);  
  
    m_strUserName = userName;  
  
    if (Send(m_cmdSocket, strCommandLine) < 0)  
    {  
        return FTP_FAILED;  
    }  
  
    m_strResponse = serverResponse(m_cmdSocket);  
    cli_app_log(CLI_LOG_INFO, "Response: %s\n", m_strResponse.c_str()); 
    if (m_strResponse.empty())
    {
        cli_app_log(CLI_LOG_NOTICE, "ftp response is empty \n");
        return FTP_FAILED;
    }
    if (parseResponse(m_strResponse) == 331)
    {
        return FTP_SUCCESS;
    }
    else
    {
        cli_app_log(CLI_LOG_NOTICE, "ftp response is not correct %s \n",  m_strResponse.c_str());
        return FTP_FAILED;
    } 
}  
  
FTP_API CFTPManager::inputPassWord(const std::string &password)  
{  
    std::string strCmdLine = parseCommand(FTP_COMMAND_PASSWORD, password);  
  
    m_strPassWord = password;  
    if (Send(m_cmdSocket, strCmdLine) < 0)  
    {  
        return FTP_FAILED;  
    }  
    else  
    {  
        m_bLogin = true;  
  
        m_strResponse = serverResponse(m_cmdSocket);  
        if (m_strResponse.empty())
        {
            cli_app_log(CLI_LOG_NOTICE, "ftp response is empty \n");
            return FTP_FAILED;
        }
        if (parseResponse(m_strResponse) == 230)
        {
            return FTP_SUCCESS;
        }
        else
        {
            cli_app_log(CLI_LOG_NOTICE, "ftp response is not correct %s \n",  m_strResponse.c_str());
            return FTP_FAILED;
        }  
    }  
}  
  
FTP_API CFTPManager::quitServer(void)  
{  
    std::string strCmdLine = parseCommand(FTP_COMMAND_QUIT, "");  
    if (Send(m_cmdSocket, strCmdLine) < 0)  
    {  
        return -1;  
    }  
    else  
    {  
        m_strResponse = serverResponse(m_cmdSocket);  
        cli_app_log(CLI_LOG_INFO, "Response: %s\n", m_strResponse.c_str());  
  
        if (m_strResponse.empty())
        {
            cli_app_log(CLI_LOG_NOTICE, "ftp response is empty \n");
            return FTP_FAILED;
        }
        if (parseResponse(m_strResponse) == 221 || parseResponse(m_strResponse) == 220)
        {
            return FTP_SUCCESS;
        }
        else
        {
            cli_app_log(CLI_LOG_NOTICE, "ftp response is not correct %s \n",  m_strResponse.c_str());
            return FTP_FAILED;
        }  

    }  
}  
  
const std::string CFTPManager::PWD()  
{  
    std::string strCmdLine = parseCommand(FTP_COMMAND_CURRENT_PATH, "");  
  
    if (Send(m_cmdSocket, strCmdLine.c_str()) < 0)  
    {  
        return "";  
    }  
    else  
    {  
        return serverResponse(m_cmdSocket);  
    }  
}  
  
  
FTP_API CFTPManager::setTransferMode(type mode)  
{  
    std::string strCmdLine;  
  
    switch (mode)  
    {  
    case binary:  
        strCmdLine = parseCommand(FTP_COMMAND_TYPE_MODE, "I");  
        break;  
    case ascii:  
        strCmdLine = parseCommand(FTP_COMMAND_TYPE_MODE, "A");  
        break;  
    default:  
        break;  
    }  
  
    if (Send(m_cmdSocket, strCmdLine.c_str()) < 0)  
    {  
        assert(false);  
    }  
    else  
    {     
        m_strResponse  = serverResponse(m_cmdSocket);  
        printf("@@@@Response: %s", m_strResponse.c_str());  
  
        return parseResponse(m_strResponse);  
    }  
}  
  
  
const std::string CFTPManager::Pasv()  
{  
    std::string strCmdLine = parseCommand(FTP_COMMAND_PSAV_MODE, "");  
  
    if (Send(m_cmdSocket, strCmdLine.c_str()) < 0)  
    {  
        return "";  
    }  
    else  
    {  
        m_strResponse = serverResponse(m_cmdSocket);  
  
        return m_strResponse;  
    }  
}  
  
  
const std::string CFTPManager::Dir(const std::string &path)  
{  
    int dataSocket = socket(AF_INET, SOCK_STREAM, 0);  
  
    if (createDataLink(dataSocket) < 0)  
    {  
        return "";  
    }  
    // 数据连接成功  
    std::string strCmdLine = parseCommand(FTP_COMMAND_DIR, path);  
  
    if (Send(m_cmdSocket, strCmdLine) < 0)  
    {  
        trace("@@@@Response: %s\n", serverResponse(m_cmdSocket).c_str());  
        close(dataSocket);  
        return "";  
    }  
    else  
    {  
        trace("@@@@Response: %s\n", serverResponse(m_cmdSocket).c_str());  
        m_strResponse = serverResponse(dataSocket);  
  
        trace("@@@@Response: \n%s\n", m_strResponse.c_str());  
        close(dataSocket);  
  
        return m_strResponse;  
    }  
      
}  
  
  
FTP_API CFTPManager::CD(const std::string &path)  
{  
    assert(m_cmdSocket != INVALID_SOCKET);  
  
    std::string strCmdLine = parseCommand(FTP_COMMAND_CHANGE_DIRECTORY, path);  
  
    if (Send(m_cmdSocket, strCmdLine) < 0)  
    {  
        return -1;  
    }  
          
    m_strResponse = serverResponse(m_cmdSocket);  
      
    trace("@@@@Response: %s\n", m_strResponse.c_str());  
    return parseResponse(m_strResponse);  
}  
  
FTP_API CFTPManager::DeleteFile(const std::string &strRemoteFile)  
{  
    assert(m_cmdSocket != INVALID_SOCKET);  
  
    std::string strCmdLine = parseCommand(FTP_COMMAND_DELETE_FILE, strRemoteFile);  
  
    if (Send(m_cmdSocket, strCmdLine) < 0)  
    {  
        return -1;  
    }  
  
    m_strResponse = serverResponse(m_cmdSocket);  
    printf("@@@@Response: %s\n", m_strResponse.c_str());  
    return parseResponse(m_strResponse);  
}  
  
FTP_API CFTPManager::DeleteDirectory(const std::string &strRemoteDir)  
{  
    assert(m_cmdSocket != INVALID_SOCKET);  
  
    std::string strCmdLine = parseCommand(FTP_COMMAND_DELETE_DIRECTORY, strRemoteDir);  
  
    if (Send(m_cmdSocket, strCmdLine) < 0)  
    {  
        return -1;  
    }  
      
    m_strResponse = serverResponse(m_cmdSocket);  
  
    trace("@@@@Response: %s\n", m_strResponse.c_str());  
    return parseResponse(m_strResponse);  
}  
  
void Ftpsplit(std::string& s, const std::string& delim, std::vector<std::string> *ret)
{
    unsigned last = 0;
    unsigned index = s.find_first_of(delim, last);
    while(index != std::string::npos)
    {
        ret->push_back(s.substr(last,index-last));
        last = index+1;
        index = s.find_first_of(delim,last);
    }

    if(index-last > 0)
    {
        ret->push_back(s.substr(last,index-last));
    }
}

FTP_API CFTPManager::StatFileOrDir(const std::string &strRemoteDir)
{
    if(m_cmdSocket == INVALID_SOCKET)
    {
        return FTP_FAILED;  
    }
    std::string strCmdLine = parseCommand(FTP_COMMAND_STAT_FILE, strRemoteDir);  
  
    if (Send(m_cmdSocket, strCmdLine) < 0)  
    {  
        return -1;  
    }  
      
    m_strResponse = serverResponse(m_cmdSocket);  
    if (m_strResponse.empty())
    {
        cli_app_log(CLI_LOG_NOTICE, "ftp response is empty \n");
        return FTP_FAILED;
    }
    cli_app_log(CLI_LOG_INFO, "stat dir Response is : %s\n", m_strResponse.c_str());

    if (parseResponse(m_strResponse) == 213)
    {
        std::string delim = "\n";
        std::vector <std::string> payload;
        Ftpsplit(m_strResponse, delim, &payload);
        if (payload.size() < 5)
        {
            cli_app_log(CLI_LOG_INFO, "msg %s \n", payload[0].c_str());
            return FTP_SUCCESS;
        }
        cli_app_log(CLI_LOG_INFO, "%s  %d file is OK \n", strRemoteDir.c_str(), payload.size());
        return FTP_DIR_EXISTS;
    }
    else if (parseResponse(m_strResponse) == 550)
    {
        return FTP_FAILED;
    }
    else
    {
        cli_app_log(CLI_LOG_NOTICE, "ftp response is not correct %s \n",  m_strResponse.c_str());
        return FTP_FAILED;
    } 

}

FTP_API CFTPManager::CreateDirectory(const std::string &strRemoteDir)  
{  
   if(m_cmdSocket == INVALID_SOCKET)
    {
        return FTP_FAILED;  
    }
  
    std::string strCmdLine = parseCommand(FTP_COMMAND_CREATE_DIRECTORY, strRemoteDir);  
  
    if (Send(m_cmdSocket, strCmdLine) < 0)  
    {  
        return -1;  
    }  
      
    m_strResponse = serverResponse(m_cmdSocket);  
    if (m_strResponse.empty())
    {
        cli_app_log(CLI_LOG_NOTICE, "ftp response is empty \n");
        return FTP_FAILED;
    }
    cli_app_log(CLI_LOG_INFO, "create dir Response is : %s\n", m_strResponse.c_str());

    if (parseResponse(m_strResponse) == 257)
    {
        cli_app_log(CLI_LOG_INFO, "%s file is OK \n", strRemoteDir.c_str());
        return FTP_SUCCESS;
    }
    else if (parseResponse(m_strResponse) == 550)
    {
        if (strstr(m_strResponse.c_str(), "already exists") != NULL)
        {
            cli_app_log(CLI_LOG_INFO, "dir is already exists\n");
            return FTP_SUCCESS;
        }
        return FTP_FAILED;
    }
    else
    {
        cli_app_log(CLI_LOG_NOTICE, "ftp response is not correct %s \n",  m_strResponse.c_str());
        return FTP_FAILED;
    } 
 
}  
  
FTP_API CFTPManager::Rename(const std::string &strRemoteFile, const std::string &strNewFile)  
{  
    if(m_cmdSocket == INVALID_SOCKET)
    {
        return FTP_FAILED;  
    }
    std::string strCmdLine = parseCommand(FTP_COMMAND_RENAME_BEGIN, strRemoteFile);  
    Send(m_cmdSocket, strCmdLine);  

    m_strResponse = serverResponse(m_cmdSocket);  
    if (m_strResponse.empty())
    {
        cli_app_log(CLI_LOG_NOTICE, "ftp response is empty \n");
        return FTP_FAILED;
    }
    
    if (parseResponse(m_strResponse) == 350)
    {
        cli_app_log(CLI_LOG_INFO, "%s file is OK \n", strRemoteFile.c_str());
    }
    else if (parseResponse(m_strResponse) == 550)
    {
        return FTP_FILE_ERROR;
    }
    else
    {
        cli_app_log(CLI_LOG_NOTICE, "ftp response is not correct %s \n",  m_strResponse.c_str());
        return FTP_FAILED;
    } 
  
    Send(m_cmdSocket, parseCommand(FTP_COMMAND_RENAME_END, strNewFile));  
  
    m_strResponse = serverResponse(m_cmdSocket);  
    cli_app_log(CLI_LOG_INFO, "@@@@Response: %s\n", m_strResponse.c_str());  
    if (m_strResponse.empty())
    {
        cli_app_log(CLI_LOG_NOTICE, "ftp response is empty \n");
        return FTP_FAILED;
    }
    if (parseResponse(m_strResponse) == 250)
    {
        return FTP_SUCCESS;
    }
    else
    {
        cli_app_log(CLI_LOG_NOTICE, "ftp response is not correct %s \n",  m_strResponse.c_str());
        return FTP_FAILED;
    } 

}  
  
long CFTPManager::getFileLength(const std::string &strRemoteFile)  
{  
    assert(m_cmdSocket != INVALID_SOCKET);  
  
    std::string strCmdLine = parseCommand(FTP_COMMAND_FILE_SIZE, strRemoteFile);  
  
    if (Send(m_cmdSocket, strCmdLine) < 0)  
    {  
        return -1;  
    }  
  
    m_strResponse = serverResponse(m_cmdSocket);  
  
    trace("@@@@Response: %s\n", m_strResponse.c_str());  
  
    std::string strData = m_strResponse.substr(0, 3);  
    unsigned long val = atol(strData.c_str());  
  
    if (val == 213)  
    {  
        strData = m_strResponse.substr(4);  
        trace("strData: %s\n", strData.c_str());  
        val = atol(strData.c_str());  
  
        return val;  
    }  
  
    return -1;  
}  
  
  
void CFTPManager::Close(int sock)  
{  
    shutdown(sock, SHUT_RDWR);  
    close(sock);  
    sock = INVALID_SOCKET;  
}  
  
FTP_API CFTPManager::Get(const std::string &strRemoteFile, const std::string &strLocalFile)  
{  
    return downLoad(strRemoteFile, strLocalFile);  
}  
  
  
FTP_API CFTPManager::Put(const std::string &strRemoteFile, const std::string &strLocalFile)  
{  
    std::string strCmdLine;  
    const unsigned long dataLen = FTP_DEFAULT_BUFFER;  
    char strBuf[dataLen] = {0};  
    long nSize = getFileLength(strRemoteFile);  
    unsigned long nLen = 0;  
//  struct stat sBuf;  
//   
//  assert(stat(strLocalFile.c_str(), &sBuf) == 0);  
//  trace("size: %d\n", sBuf.st_size);  
  
    FILE *pFile = fopen(strLocalFile.c_str(), "rb");  // 以只读方式打开  且文件必须存在  
    assert(pFile != NULL);  
  
    int data_fd = socket(AF_INET, SOCK_STREAM, 0);  
    assert(data_fd != -1);  
  
    if (createDataLink(data_fd) < 0)  
    {  
        return -1;  
    }  
      
    if (nSize == -1)  
    {  
        strCmdLine = parseCommand(FTP_COMMAND_UPLOAD_FILE, strRemoteFile);  
    }  
    else  
    {  
        strCmdLine = parseCommand(FTP_COMMAND_APPEND_FILE, strRemoteFile);  
    }  
  
    if (Send(m_cmdSocket, strCmdLine) < 0)  
    {  
        Close(data_fd);  
        return -1;  
    }  
  
    trace("@@@@Response: %s\n", serverResponse(m_cmdSocket).c_str());  
  
    fseek(pFile, nSize, SEEK_SET);  
    while (!feof(pFile))  
    {  
        nLen = fread(strBuf, 1, dataLen, pFile);  
        if (nLen < 0)  
        {  
            break;  
        }  
  
        if (Send(data_fd, strBuf) < 0)  
        {  
            Close(data_fd);  
            return -1;  
        }  
    }  
  
    trace("@@@@Response: %s\n", serverResponse(data_fd).c_str());  
  
    Close(data_fd);  
    trace("@@@@Response: %s\n", serverResponse(m_cmdSocket).c_str());  
    fclose(pFile);  
  
    return 0;  
}  
  
const std::string CFTPManager::parseCommand(const unsigned int command, const std::string &strParam)  
{  
    if (command < FTP_COMMAND_BASE || command > FTP_COMMAND_END)  
    {  
        return "";  
    }  
  
    std::string strCommandLine;  
  
    m_nCurrentCommand = command;  
    m_commandStr.clear();  
  
    switch (command)  
    {  
    case FTP_COMMAND_USERNAME:  
        strCommandLine = "USER ";  
        break;  
    case FTP_COMMAND_PASSWORD:  
        strCommandLine = "PASS ";  
        break;  
    case FTP_COMMAND_QUIT:  
        strCommandLine = "QUIT ";  
        break;  
    case FTP_COMMAND_CURRENT_PATH:  
        strCommandLine = "PWD ";  
        break;  
    case FTP_COMMAND_TYPE_MODE:  
        strCommandLine = "TYPE ";  
        break;  
    case FTP_COMMAND_PSAV_MODE:  
        strCommandLine = "PASV ";  
        break;  
    case FTP_COMMAND_DIR:  
        strCommandLine = "LIST ";  
        break;  
    case FTP_COMMAND_CHANGE_DIRECTORY:  
        strCommandLine = "CWD ";  
        break;  
    case FTP_COMMAND_DELETE_FILE:  
        strCommandLine = "DELE ";  
        break;  
    case FTP_COMMAND_DELETE_DIRECTORY:  
        strCommandLine = "RMD ";  
        break;  
    case FTP_COMMAND_CREATE_DIRECTORY:  
        strCommandLine = "MKD ";  
        break;  
    case FTP_COMMAND_RENAME_BEGIN:  
        strCommandLine = "RNFR ";  
        break;  
    case FTP_COMMAND_RENAME_END:  
        strCommandLine = "RNTO ";  
        break;  
    case FTP_COMMAND_FILE_SIZE:  
        strCommandLine = "SIZE ";  
        break;  
    case FTP_COMMAND_DOWNLOAD_FILE:  
        strCommandLine = "RETR ";  
        break;  
    case FTP_COMMAND_DOWNLOAD_POS:  
        strCommandLine = "REST ";  
        break;  
    case FTP_COMMAND_UPLOAD_FILE:  
        strCommandLine = "STOR ";  
        break;  
    case FTP_COMMAND_APPEND_FILE:  
        strCommandLine = "APPE ";  
        break;  

    case FTP_COMMAND_STAT_FILE:
        strCommandLine = "STAT ";  
        break;  
       
    default :  
        break;  
    }  
  
    strCommandLine += strParam;  
    strCommandLine += "\r\n";  
  
    m_commandStr = strCommandLine;  
    cli_app_log(CLI_LOG_INFO, "parseCommand: %s\n", m_commandStr.c_str());  
  
    return m_commandStr;  
}  
  
FTP_API CFTPManager::Connect(int socketfd, const std::string &serverIP, unsigned int nPort)  
{  
    if (socketfd == INVALID_SOCKET)  
    {  
        return -1;  
    }  
  
    unsigned int argp = 1;  
    int error = -1;  
    int len = sizeof(int);  
    struct sockaddr_in  addr;  
    bool ret = false;  
    timeval stime;  
    fd_set  set;  
  
    ioctl(socketfd, FIONBIO, &argp);  //设置为非阻塞模式  
  
    memset(&addr, 0, sizeof(struct sockaddr_in));  
    addr.sin_family = AF_INET;  
    addr.sin_port   = htons(nPort);  
    addr.sin_addr.s_addr = inet_addr(serverIP.c_str());  
    bzero(&(addr.sin_zero), 8);  
  
    trace("Address: %s %d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));  
      
    if (connect(socketfd, (struct sockaddr*)&addr, sizeof(struct sockaddr)) == -1)   //若直接返回 则说明正在进行TCP三次握手  
    {  
        stime.tv_sec = 5;  //设置为1秒超时  
        stime.tv_usec = 0;  
        FD_ZERO(&set);  
        FD_SET(socketfd, &set);  
  
        if (select(socketfd + 1, NULL, &set, NULL, &stime) > 0)   ///在这边等待 阻塞 返回可以读的描述符 或者超时返回0  或者出错返回-1  
        {  
            getsockopt(socketfd, SOL_SOCKET, SO_ERROR, &error, (socklen_t*)&len);  
            if (error == 0)  
            {  
                ret = true;  
            }  
            else  
            {  
                ret = false;  
            }  
        }  
    }  
    else  
    {   trace("Connect Immediately!!!\n");  
        ret = true;  
    }  
  
    argp = 0;  
    ioctl(socketfd, FIONBIO, &argp);  
  
    if (!ret)  
    {  
        close(socketfd);  
        fprintf(stderr, "cannot connect server!!\n");  
        return -1;  
    }  
  
    //fprintf(stdout, "Connect!!!\n");  
  
    return 0;  
}  
  
  
const std::string CFTPManager::serverResponse(int sockfd)  
{  
    if (sockfd == INVALID_SOCKET)  
    {  
        return "";  
    }  
      
    int nRet = -1;  
    char buf[MAX_PATH] = {0};  
  
    m_strResponse.clear();  
  
    while ((nRet = getData(sockfd, buf, MAX_PATH)) > 0)  
    {  
        buf[MAX_PATH - 1] = '\0';  
        m_strResponse += buf;  
    }  
  
    return m_strResponse;  
}  
  
FTP_API CFTPManager::getData(int fd, char *strBuf, unsigned long length)  
{  
    assert(strBuf != NULL);  
  
    if (fd == INVALID_SOCKET)  
    {  
        return -1;  
    }  
  
    memset(strBuf, 0, length);  
    timeval stime;  
    int nLen;  
  
    stime.tv_sec = 0;  
    stime.tv_usec = 500000;  
  
    fd_set  readfd;  
    FD_ZERO( &readfd );  
    FD_SET(fd, &readfd );  
  
    if (select(fd + 1, &readfd, 0, 0, &stime) > 0)  
    {  
        if ((nLen = recv(fd, strBuf, length, 0)) > 0)  
        {  
            return nLen;  
        }  
        else  
        {  
            return -2;  
        }  
    }  
    return 0;  
}  
  
FTP_API CFTPManager::Send(int fd, const std::string &cmd)  
{  
    if (fd == INVALID_SOCKET)  
    {  
        return -1;  
    }  
  
    return Send(fd, cmd.c_str(), cmd.length());  
}  
  
FTP_API CFTPManager::Send(int fd, const char *cmd, const size_t len)  
{  
    if((FTP_COMMAND_USERNAME != m_nCurrentCommand)   
        &&(FTP_COMMAND_PASSWORD != m_nCurrentCommand)  
        &&(!m_bLogin))  
    {  
        return -1;  
    }  
  
    timeval timeout;  
    timeout.tv_sec  = 1;  
    timeout.tv_usec = 0;  
  
    fd_set  writefd;  
    FD_ZERO(&writefd);    
    FD_SET(fd, &writefd);  
  
    if(select(fd + 1, 0, &writefd , 0 , &timeout) > 0)  
    {  
        size_t nlen  = len;   
        int nSendLen = 0;   
        while (nlen >0)   
        {  
            nSendLen = send(fd, cmd , (int)nlen , 0);  
  
            if(nSendLen == -1)   
                return -2;   
  
            nlen = nlen - nSendLen;  
            cmd +=  nSendLen;  
        }  
        return 0;  
    }  
    return -1;  
}  
  
  
FTP_API CFTPManager::createDataLink(int data_fd)  
{  
    assert(data_fd != INVALID_SOCKET);  
  
    std::string strData;  
    unsigned long nPort = 0 ;  
    std::string strServerIp ;   
    std::list<std::string> strArray ;  
  
    std::string parseStr = Pasv();  
  
    if (parseStr.size() <= 0)  
    {  
        return -1;  
    }  
  
    //trace("parseInfo: %s\n", parseStr.c_str());  
  
    size_t nBegin = parseStr.find_first_of("(");  
    size_t nEnd   = parseStr.find_first_of(")");  
    strData       = parseStr.substr(nBegin + 1, nEnd - nBegin - 1);  
  
    //trace("ParseAfter: %s\n", strData.c_str());  
    if( SplitString( strData , strArray , "," ) <0)  
        return -1;  
  
    if( ParseString( strArray , nPort , strServerIp) < 0)  
        return -1;  
  
    //trace("nPort: %ld IP: %s\n", nPort, strServerIp.c_str());  
  
    if (Connect(data_fd, strServerIp, nPort) < 0)  
    {  
        return -1;  
    }  
  
    return 0;  
  
}  
  
FTP_API CFTPManager::ParseString(std::list<std::string> strArray, unsigned long & nPort ,std::string & strServerIp)  
{  
    if (strArray.size() < 6 )  
        return -1 ;  
  
    std::list<std::string>::iterator citor;  
    citor = strArray.begin();  
    strServerIp = *citor;  
    strServerIp += ".";  
    citor ++;  
    strServerIp += *citor;  
    strServerIp += ".";  
    citor ++ ;  
    strServerIp += *citor;  
    strServerIp += ".";  
    citor ++ ;  
    strServerIp += *citor;  
    citor = strArray.end();  
    citor--;  
    nPort = atol( (*citor).c_str());  
    citor--;  
    nPort += atol( (*(citor)).c_str()) * 256 ;  
    return 0 ;   
}  
  
FILE *CFTPManager::createLocalFile(const std::string &strLocalFile)  
{  
    return fopen(strLocalFile.c_str(), "w+b");  
}  
  
FTP_API CFTPManager::downLoad(const std::string &strRemoteFile, const std::string &strLocalFile, const int pos, const unsigned int length)  
{  
    assert(length >= 0);  
  
    FILE *file = NULL;  
    unsigned long nDataLen = FTP_DEFAULT_BUFFER;  
    char strPos[MAX_PATH]  = {0};  
    int data_fd = socket(AF_INET, SOCK_STREAM, 0);  
      
    assert(data_fd != -1);  
  
    if ((length != 0) && (length < nDataLen))  
    {  
        nDataLen = length;  
    }  
    char *dataBuf = new char[nDataLen];  
    assert(dataBuf != NULL);  
  
    sprintf(strPos, "%d", pos);  
  
    if (createDataLink(data_fd) < 0)  
    {  
        trace("@@@@ Create Data Link error!!!\n");  
        return -1;  
    }  
  
    std::string strCmdLine = parseCommand(FTP_COMMAND_DOWNLOAD_POS, strPos);  
    if (Send(m_cmdSocket, strCmdLine) < 0)  
    {  
        return -1;  
    }  
    trace("@@@@Response: %s\n", serverResponse(m_cmdSocket).c_str());  
  
    strCmdLine = parseCommand(FTP_COMMAND_DOWNLOAD_FILE, strRemoteFile);  
  
    if (Send(m_cmdSocket, strCmdLine) < 0)  
    {  
        return -1;  
    }  
    trace("@@@@Response: %s\n", serverResponse(m_cmdSocket).c_str());  
  
    file = createLocalFile(std::string(FTP_DEFAULT_PATH + strLocalFile));  
    assert(file != NULL);  
      
    int len = 0;  
    int nReceiveLen = 0;  
    while ((len = getData(data_fd, dataBuf, nDataLen)) > 0)  
    {  
        nReceiveLen += len;  
  
        int num = fwrite(dataBuf, 1, len, file);  
        memset(dataBuf, 0, sizeof(dataBuf));  
      
        //trace("%s", dataBuf);  
        trace("Num:%d\n", num);  
        if (nReceiveLen == length && length != 0)  
            break;  
  
        if ((nReceiveLen + nDataLen) > length  && length != 0)  
        {  
            delete []dataBuf;  
            nDataLen = length - nReceiveLen;  
            dataBuf = new char[nDataLen];  
        }  
    }  
  
    Close(data_fd);  
    fclose(file);  
    delete []dataBuf;  
  
    return 0;  
}  
  
FTP_API CFTPManager::parseResponse(const std::string &str)  
{  
    assert(!str.empty());  
  
    std::string strData = str.substr(0, 3);  
    unsigned int val = atoi(strData.c_str());  
  
    return val;  
} 
